package com.lin.filegraph.utils.parser.astvisitor;

import com.lin.filegraph.utils.parser.node.JClassNode;
import com.lin.filegraph.utils.parser.node.JEnumNode;
import com.lin.filegraph.utils.parser.node.JFileNode;
import com.lin.filegraph.utils.parser.node.JInterfaceNode;
import org.eclipse.jdt.core.dom.*;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

/**
 * @description:
 * @author: linhuaixu
 * @time: 2023/5/18 14:08
 */

public class TypeVisitor extends ASTVisitor {

    private CompilationUnit compilationUnit;
    private String filePath;
    private JFileNode fileNode;

    public TypeVisitor(JFileNode fileNode) {
        // TODO Auto-generated constructor stub
        this.fileNode = fileNode;
        this.filePath = fileNode.getFilePath();
        this.compilationUnit = fileNode.getCompilationUnit();
    }

    @Override
    public boolean visit(TypeDeclaration node) {
        // Ѱ����ͨ�ࡢ�ӿڡ��������ڲ��࣬����ClassNode�������࣬��������Ϊ��Ӧ���ļ��ڵ���ӽڵ�
        // ͬʱѰ����Field��Method�б���������Ӧ��FieldNode��MethodNode��������ΪClassNode���ӽڵ�
        String strSuperClassName = null;
        String strOuterTypeName = null;
        List<String> listStrSuperInterface = new ArrayList<String>();
        if (node.resolveBinding() != null) {
            String typeName = node.resolveBinding().getBinaryName();
            String modifier = Modifier.toString(node.resolveBinding().getModifiers());
            boolean isInterface = node.resolveBinding().isInterface();
            boolean isClass = node.resolveBinding().isClass();
            boolean isAnonymous = node.resolveBinding().isAnonymous();
            boolean isGeneric = false;
            if (!node.typeParameters().isEmpty()) {
                isGeneric = true;
            }
            if (node.resolveBinding().getSuperclass() != null) {
                strSuperClassName = node.resolveBinding().getSuperclass().getBinaryName();
            }
            if (node.resolveBinding().getDeclaringClass() != null) {
                strOuterTypeName = node.resolveBinding().getDeclaringClass().getBinaryName();
            }
            for (ITypeBinding iTypeBinding : node.resolveBinding().getInterfaces()) {
                listStrSuperInterface.add(iTypeBinding.getBinaryName());
            }
            if (isClass && typeName != null && !typeName.isEmpty()) {
                JClassNode classNode = new JClassNode(filePath, node, typeName, modifier, strOuterTypeName,
                        listStrSuperInterface, isAnonymous, strSuperClassName);
                classNode.isGeneric = isGeneric;
                fileNode.addChildNode(classNode);
            }
            if (isInterface && typeName != null && !typeName.isEmpty()) {
                JInterfaceNode interfaceNode = new JInterfaceNode(filePath, node, typeName, modifier, strOuterTypeName,
                        listStrSuperInterface);
                interfaceNode.isGeneric = isGeneric;
                fileNode.addChildNode(interfaceNode);
            }
        }
        return true;
    }

    @Override
    public boolean visit(EnumDeclaration node) {
        // Ѱ��ö����
        String strOuterTypeName = null;
        List<String> listStrSuperInterface = new ArrayList<String>();
        if (node.resolveBinding() != null) {
            String enumName = node.resolveBinding().getBinaryName();
            String modifier = Modifier.toString(node.resolveBinding().getModifiers());
            if (node.resolveBinding().getDeclaringClass() != null) {
                strOuterTypeName = node.resolveBinding().getDeclaringClass().getBinaryName();
            }
            for (ITypeBinding iTypeBinding : node.resolveBinding().getInterfaces()) {
                listStrSuperInterface.add(iTypeBinding.getBinaryName());
            }
            if (enumName != null && !enumName.isEmpty()) {
                JEnumNode enumNode = new JEnumNode(filePath, node, enumName, modifier, strOuterTypeName,
                        listStrSuperInterface);
                fileNode.addChildNode(enumNode);
            }

        }
        return true;
    }

    @Override
    public boolean visit(AnonymousClassDeclaration node) {
        // Ѱ��������,��������Ϊ��Ӧ���ļ��ڵ���ӽڵ�
        String strSuperClassName = null;
        String strOuterTypeName = null;
        List<String> listStrSuperInterface = new ArrayList<String>();
        if (node.resolveBinding() != null) {
            String className = node.resolveBinding().getBinaryName();
            String modifier = Modifier.toString(node.resolveBinding().getModifiers());
            if (className == null) {
                className = node.resolveBinding().getKey();
            }
            if (node.resolveBinding().getSuperclass() != null) {
                strSuperClassName = node.resolveBinding().getSuperclass().getBinaryName();
            }
            if (node.resolveBinding().getDeclaringClass() != null) {
                strOuterTypeName = node.resolveBinding().getDeclaringClass().getBinaryName();
            }
            for (ITypeBinding iTypeBinding : node.resolveBinding().getInterfaces()) {
                listStrSuperInterface.add(iTypeBinding.getBinaryName());
            }

            if (className != null && !className.isEmpty()) {
                JClassNode classNode = new JClassNode(filePath, node, className, modifier, strOuterTypeName,
                        listStrSuperInterface, true, strSuperClassName);
                fileNode.addChildNode(classNode);
            }

        }
        return true;
    }

    public void traverse() {
        compilationUnit.accept(this);
    }
}

